package pers.richard.ormybatis.bean.sql;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.github.pagehelper.PageHelper;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import pers.richard.ormybatis.bean.AbstractDomain;
import pers.richard.ormybatis.bean.field.FieldName;
import pers.richard.ormybatis.bean.field.IField;

/**
 * Where语句构造器
 */
public class Where extends AbstractDomain {
	private List<OperationExpressionBean> operExpressList = new ArrayList<OperationExpressionBean>();
	private List<OrderByBean> orderByList = new ArrayList<OrderByBean>();
	private Integer limitIndex = 0;
	private Integer limitSize;
	private boolean ignoredValueNull = false;

	private Where() {}

	public static Where create() {
		return new Where();
	}

	public static Where create(IField Field, Object value) {
		return new Where().eq(Field, value);
	}

	/**
	 *	注入sql 如:eval("name = 18") 或 eval("name = {}", 18) 
	 */
	public Where eval(CharSequence sqlTemplate, Object... params) {
		String sql = StrUtil.format(sqlTemplate, params);
		return this.setOperationExpression(new FieldName(sql), "eval", null);
	}
	
	/**
	 * 等于 (=) 默认
	 */
	public Where eq(IField Field, Object value) {
		if (value instanceof Collection) {
			Collection coll = (Collection) value;
			return this.in(Field, coll);
		}
		return this.setOperationExpression(Field, "=", value);
	}

	/**
	 * 不等于 (<>) 默认
	 */
	public Where notEq(IField Field, Object value) {
		return this.setOperationExpression(Field, "<>", value);
	}

	/**
	 * <pre>
	 * Map map = (abc, v1), (XYZ, v2), (abcXyz, v2)
	 * 效果同
	 * abc = v1 AND XYZ = v2 AND abc_xyz = v3
	 * </pre>
	 */
	public Where eq(Map paramMap) {
		if (paramMap == null || paramMap.isEmpty()) {
			return this;
		}
		for (Object keyField : paramMap.keySet()) {
			String value = MapUtil.getStr(paramMap, keyField);
			if (StrUtil.isBlank(value)) {
				continue;
			}
			FieldName fieldName = new FieldName(keyField.toString());
			this.eq(fieldName, value);
		}
		return this;
	}

	/**
	 * <pre>
	 * User u = new User().setId(1).setName("jack")
	 * 效果同
	 * id = 1 AND name = jack
	 * </pre>
	 */
	public Where eq(Object bean) {
		Map<String, Object> map = BeanUtil.beanToMap(bean);
		return this.eq(map);
	}

	/**
	 * 大于(>)
	 */
	public Where gt(IField Field, Object value) {
		return this.setOperationExpression(Field, ">", value);
	}

	/**
	 * 大于等于(>=)
	 */
	public Where gte(IField Field, Object value) {
		return this.setOperationExpression(Field, ">=", value);
	}

	/**
	 * 小于(<)
	 */
	public Where lt(IField Field, Object value) {
		return this.setOperationExpression(Field, "<", value);
	}

	/**
	 * 小于等于(<=)
	 */
	public Where lte(IField Field, Object value) {
		return this.setOperationExpression(Field, "<=", value);
	}

	/**
	 * like查询(% + value + %)
	 */
	public Where like(IField Field, Object value) {
		return this.setOperationExpression(Field, "like", value);
	}

	/**
	 * like查询(value + %)
	 */
	public Where likeLeft(IField Field, Object value) {
		return this.setOperationExpression(Field, "like_left", value);
	}

	/**
	 * like查询(% + value)
	 */
	public Where likeRight(IField Field, Object value) {
		return this.setOperationExpression(Field, "like_right", value);
	}

	/**
	 * 日期范围查询,入参如果没小时部分自动精确到一天的开始和结束时间的秒
	 * <pre>
	 * AND field >= startDate
	 * AND field <= endDate
	 * </pre>
	 * @param field 字段名
	 * @param start  开始日期
	 * @param end 结束日期
	 * @param format mysql sql的日期格式
	 */
	public Where betweenDate(IField Field, String start, String end) {
		if (StrUtil.isNotBlank(start)) {
			start = this.getStartFullDate(start);
			this.setOperationExpression(Field, ">=", start);
		}
		if (StrUtil.isNotBlank(end)) {
			end = this.getEndFullDate(end);
			this.setOperationExpression(Field, "<=", end);
		}
		return this;
	}

	/**
	 * IN (xxx,yyy)
	 */
	public Where in(IField Field, Object... values) {
		if (ArrayUtil.isEmpty(values)) {
			return this;
		}
		List listValues = Arrays.asList(values);
		return this.in(Field, listValues);
	}

	/**
	 * IN (xxx,yyy)
	 */
	public Where in(IField Field, Collection values) {
		if (CollUtil.isEmpty(values)) {
			return this;
		}
		return this.setOperationExpression(Field, "in", values);
	}

	/**
	 * IS NULL
	 */
	public Where isNull(IField Field) {
		return this.setOperationExpression(Field, "is_null", null);
	}

	/**
	 * IS NOT NULL
	 */
	public Where isNotNull(IField Field) {
		return this.setOperationExpression(Field, "is_not_null", null);
	}

	/**
	 * LIMIT limitSize
	 */
	public Where limit(int limitSize) {
		this.limit(0, limitSize);
		return this;
	}

	/**
	 * 分页Limit
	 * @param pageIndex  第几页
	 * @param pageSize 每页记录数
	 * @return
	 */
	public Where limitPage(Integer pageIndex, Integer pageSize) {
		int limitIndex = (pageIndex - 1) * pageSize;
		if (limitIndex < 0) {
			limitIndex = 0;
		}
		this.limit(limitIndex, pageSize);
		return this;
	}
	
	/**
	 * LIMIT limitIndex, limitSize
	 */
	public Where limit(int limitIndex, int limitSize) {
		if (PageHelper.getLocalPage() != null) {
			return this;
		}
		this.limitIndex = ((limitIndex < 0) ? 0 : limitIndex);
		this.limitSize = limitSize;
		return this;
	}

	/**
	 * order by field_name desc
	 */
	public Where orderDesc(IField Field) {
		orderByList.add(new OrderByBean(Field.toString(), "DESC"));
		return this;
	}

	/**
	 * order by field_name asc
	 */
	public Where orderAsc(IField Field) {
		orderByList.add(new OrderByBean(Field.toString(), "ASC"));
		return this;
	}

	/**
	 * 设置查询条件值value为空,则忽略
	 * @param isNotEmpty true表示忽略为value为空的查询
	 */
	public Where ignoredValueNull(boolean ignoredValueNull) {
		this.ignoredValueNull = ignoredValueNull;
		return this;
	}

	/**
	 * 判断查询条件lis不为空
	 */
	public boolean isEmptyOperExpressList() {
		return CollUtil.isEmpty(this.operExpressList);
	}

	/**
	 * 设置条件
	 * @param field 字段名符
	 * @param oper 操作运算
	 * @param value 值
	 * @return
	 */
	private Where setOperationExpression(IField Field, String oper, Object value) {
		if (this.ignoredValueNull) {
			if (ObjectUtil.isEmpty(value)) {
				return this;
			}
		}
		if (value instanceof String) {
			value = StrUtil.trim((String) value);
		}
		OperationExpressionBean bean = new OperationExpressionBean(Field.toString(), oper, value);
		operExpressList.add(bean);
		return this;
	}

	public List<OperationExpressionBean> getOperExpressList() {
		return operExpressList;
	}

	public void setOperExpressList(List<OperationExpressionBean> operExpressList) {
		this.operExpressList = operExpressList;
	}

	public List<OrderByBean> getOrderByList() {
		return orderByList;
	}

	public void setOrderByList(List<OrderByBean> orderByList) {
		this.orderByList = orderByList;
	}

	public Integer getLimitIndex() {
		return limitIndex;
	}

	public void setLimitIndex(Integer limitIndex) {
		this.limitIndex = limitIndex;
	}

	public Integer getLimitSize() {
		return limitSize;
	}

	public void setLimitSize(Integer limitSize) {
		this.limitSize = limitSize;
	}
	
	/**
	 *	得到一个按完整的日期开始格式
	 * @param dateStr 日期各种格式字符串
	 * @return yyyy-MM-dd HH:mm:ss
	 */
	private String getStartFullDate(String dateStr) {
		dateStr = ReUtil.replaceAll(dateStr, "\\D", "");//排除除数字外的所有字符
		int len = dateStr.length();
		String format = DatePattern.PURE_DATETIME_PATTERN.substring(0, len);
		return DateUtil.parse(dateStr, format).toString();
	}
	
	/**
	 *	得到一个按完整的日期的结束时间
	 * @param dateStr 日期各种格式字符串
	 * @return yyyy-MM-dd HH:mm:ss
	 */
	private String getEndFullDate(String dateStr) {
		dateStr = ReUtil.replaceAll(dateStr, "\\D", "");//排除除数字外的所有字符
		int len = dateStr.length();
		String format = DatePattern.PURE_DATETIME_PATTERN.substring(0, len);
		Date d = DateUtil.parse(dateStr, format).toJdkDate();
		if (len == 4) {//精确到年
			return DateUtil.endOfYear(d).toString();
		} else if (len == 6) {//精确到月
			return DateUtil.endOfMonth(d).toString();
		} else if (len == 8) {//精确到天
			return DateUtil.endOfDay(d).toString();
		} else if (len == 10) {//精确到小时
			return DateUtil.parse(dateStr + "2359", DatePattern.PURE_DATETIME_PATTERN).toString();
		} else if (len == 12) {//精确到分
			return DateUtil.parse(dateStr + "59", DatePattern.PURE_DATETIME_PATTERN).toString();
		}
		return DateUtil.parse(dateStr, DatePattern.PURE_DATETIME_PATTERN).toString();
	}

}